package jvs.sh;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import jvs.peer.WebAdapter;
import jvs.peer.io.ChannelManager;
import jvs.peer.util.Log;
import jvs.sh.cmd.Handler;

import org.json.JSONObject;

/**
 * @author qiangli
 * 
 */
public class CommandInterpreter implements Interpreter {
	private static Map<String, Handler> handlers = new HashMap<String, Handler>();
	
	private final String crlf = "\r\n";

	private Console console;

	private WebAdapter adapter;

	public CommandInterpreter(WebAdapter adapter) {
		this.adapter = adapter;
	}

	public void parse(String req) {

		if (Log.DEBUG) {
			Log.log(this, "parse input: " + req);
		}
		try {
			if (req == null || req.length() == 0) {
				return;
			}
			String cmdline = null;
			String data = null;
			int idx = req.indexOf("\r\n");
			int tlen = 1;
			if (idx == -1) {
				idx = req.indexOf("\n");
				if (idx == -1) {
					idx = req.indexOf("\r");
				}
			} else {
				tlen = 2;
			}
			if (idx == -1) {
				cmdline = req;
			} else {
				cmdline = req.substring(0, idx);
				idx += tlen;
				if (req.length() > idx) {
					data = req.substring(idx);
				}
			}

			String cmd = null;
			String param = null;

			// parse command
			String[] sa = split(cmdline, 2);
			cmd = (sa.length == 0) ? null : sa[0].toUpperCase();
			param = (sa.length > 1) ? sa[1] : null;

			//
			if (cmd != null && cmd.length() > 0) {
				String dec = data == null ? null : decode(data);
				String[] args = (param == null ? null : split(param, Integer.MAX_VALUE));
				execute(cmd, args, dec);
			}
		} catch (Throwable e) {;
			err("Oops " + e);
		}
	}

	private String[] split(String s, int limit) {
		if (s == null) {
			return new String[0];
		}
		s = s.trim();
		if (s.length() == 0) {
			return new String[0];
		}
		String[] sa = s.split("\\s+", limit);
		return sa;
	}

	protected void print(String s) {
		out(s);
	}

	protected void err(String msg) {
		console.err(msg + " [Website Bot] " + crlf);
	}

	protected void ok(String s) {
		console.ok(s + crlf);
	}

	private void out(String s) {
		console.out(s + crlf);
	}

	public void setConsole(Console console) {
		this.console = console;
	}

	public void setShell(IShell shell) {
		//this.shell = shell;
	}

	protected void execute(final String line, final String[] args, final String data)
			throws Exception {
		if (Log.DEBUG) {
			Log.log(this, "execute cmd: " + line + " args: " + args
					+ " last access: ");
		}
		
		// line not null
		int idx = line.lastIndexOf("/");
		String cmd = (idx > 0) ? line.substring(idx + 1) : line;
		//
		//
		if (cmd.equals("CONNECT")) {
			connect();
		} else if (cmd.equals("EXIT")) {
			bye();
		} else if (cmd.equals("IP")) {
			ip(args, data);
		} else if (cmd.equals("GET")) {
			get(args, data);
		} else if (cmd.equals("EXEC")) {
			exec(args, data);
		} else {
			ni(cmd);
		}
	}

	private void get(String[] args, String data) throws Exception {
		if (adapter == null) {
			err("No XMPP adapter");
			return;
		}
		final String cid = args[0];

		try {
	
			JSONObject json = new JSONObject(data);

			json.put("cid", cid);

			//reply first
			String js = json.toString();
			okEncode(cid + crlf + js);
			
			if (Log.DEBUG) {
				Log.log(this, "" + js);
			}
			
			//send data
			adapter.upload(json);
		} catch (Exception e) {
			errEncode(cid + crlf + e.getLocalizedMessage());
		}
	}

	private void exec(String[] args, String data) {
		try {
			Handler h = handlers.get(args[0]);
			if (h == null) {
				err("No handlers");
				return;
			}
			h.handle(args, data);
		} catch (Exception e) {
			err(e.getMessage());
		}
	}

	private void connect() {
		ok("Welcome. ");
	}

	private void bye() throws Exception {
		ok("Bye ");
	}

	private void ip(String[] args, String data) throws Exception {
		final String cid = args[0];

		try {
			JSONObject json = new JSONObject(data);
			json.put("cid", cid);

			//
			ChannelManager man = ChannelManager.getInstance(adapter.getNetwork());
			json.put("ip", man.getIp());
			json.put("port", man.getPort());

			String js = json.toString();
			okEncode(cid + crlf + js);
			
			if (Log.DEBUG) {
				Log.log(this, "ip: " + js);
			}
		} catch (Exception e) {
			errEncode(cid + crlf + e.getLocalizedMessage());
		}
	}

	private void ni(String cmd) {
		err(cmd + " not supported.");
	}
	
	private void okEncode(String s) throws Exception {
		ok(encode(s));
	}
	
	private void errEncode(String s) throws Exception {
		err(encode(s));
	}
	
	private String encode(String s) throws UnsupportedEncodingException {
		return URLEncoder.encode(s, "UTF-8");
	}
	
	private String decode(String s) throws Exception {
		return URLDecoder.decode(s, "UTF-8");
	}
}
